﻿using System;
using System.ServiceModel;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel.Channels;

namespace Server {
	// Service class that implements the service contract.
	// Added code to write output to the console window.

	[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = true, AutomaticSessionShutdown = true)]
	public class ServiceModelServer : IServiceModelServer {
		private IServiceModelServerCallback callback = null;
		protected Guid guid;

		public ServiceModelServer() {
			Logger.Log("Starting new service model Server class...");

			callback = OperationContext.Current.GetCallbackChannel<IServiceModelServerCallback>();
			guid = Guid.NewGuid();

			OperationContext context = OperationContext.Current;
			MessageProperties messageProperties = context.IncomingMessageProperties;
			RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

			Node node = Server.Instance.AddNode(guid, this);
			if (null != node) {
				node.Ip = System.Net.IPAddress.Parse(endpointProperty.Address);
				node.Port = endpointProperty.Port;
			}
		}

		public IServiceModelServerCallback GetCallback() {
			return callback;
		}

		public Boolean TestConnection() {
			Logger.Debug(String.Format("#{1}: Connection Testing '{0}'", this.GetType().Name, guid.ToString()));

			BackgroundWorker backgroundWorker = new BackgroundWorker();

			backgroundWorker.DoWork += (o, e) => {
				try {
					Logger.Debug("Response from client: '" + callback.TestConnection().ToString() + "'");
				} catch (TimeoutException) {
					Logger.Warning("Timeout for " + guid.ToString());
					Server.Instance.RemoveNode(guid);
				} catch (CommunicationException) {
					Logger.Warning("Connection to " + guid.ToString() + " failed");
					Server.Instance.RemoveNode(guid);
				}
			};

			return true;
		}

		public void Disconnect() {
			Logger.Info("Node '" + guid + "' has been gracefully disconnected");
			Server.Instance.RemoveNode(guid);
			callback = null;
		}

		public Guid Reconnect(Guid old) {
			// Attach
			// cachuj trochę info o maszynie w nodzie (wifi state, node status)
			// removenode wcale nie usuwa noda, tylko instancję servicemodel, która jest faulted/closed
			// ustawia czas odłączenia i nie zwraca więcej go w getNodes, po X minutach usuwa
			// LUB ustawia flagę DISCONNECTED i na liście pojawia się np. na czerwono (na dole nodes active/all)
			// na żółto te, które wykonują jakąś komendę (?) PROCESSING
			// select all wybiera tylko z flagą CONNECTED!
			// podział na CONNECTED i PROCESSING (procesing jako inna flaga w sensie connected = bool i processing = bool) poprzez grupy ? w listview?
			//todo
			return Guid.Empty;
		}

		public Guid Guid {
			get {
				return guid;
			}
		}

		public void TestResultReady(Guid testGuid) {
			if (Server.Instance.NodeControl(guid).ContainsResult(testGuid)) {
				Server.Instance.NodeControl(guid).GetTestResult(testGuid);
			}
		}

		~ServiceModelServer() {
			Logger.Log("Destructing service model, guid: " + guid.ToString());
		}
	}
}
